(load "lib.lisp")

;; Utils
(defmacro myprint (var &key (newline nil) (indent 0) (name nil) (raw nil))
  "A nice debugging macro that prints out the value of var with indentation etc."
  `(progn
     (dotimes (i ,indent) (format t "   "))
       ,(if raw `(format t ,(concatenate 'string var "~%"))
         `(format t ,(concatenate 'string
                             (if name name (symbol-name var))
                             ": ~a~%")
             ,var))
       (when ,newline
         (dotimes (i ,indent) (format t "   "))
         (format t "--~%")))
  ;`nil ; uncomment this line to turn off printing
  )


(defun multiplep (q p)
	(cond
		((= p 0) nil)
		((= q 0) t)
		((< q 0) nil)
		(t (multiplep (- q p) p))))

(defun euler1 (num)
	(cond
		((> num 1000) nil)
		((or (multiplep num 3) (multiplep num 5)) (cons num (euler1 (1+ num))))
		(t (euler1 (1+ num)))))

(defun euler2 (num1 num2)
	(cond
		((> num2 4e6) 0)
		((evenp num2) (+ num2 (euler2 num2 (+ num1 num2))))
		(t (euler2 num2 (+ num1 num2)))))

(defun smallest-factor (num)
	(dotimes (f (1+ num))
		(if (and (> f 1) (multiplep num f))
			(return f))))

(defun euler3 (num)
	(cond
		((= num 1) nil)
		(t (let ((fac (smallest-factor num)))
			(cons fac (euler3 (/ num fac)))))))

(defun euler5 (l &optional (depth 1))
  (format t "l:~D d:~D~D" l depth #\Newline)
  (cond
   ((null l) 1)
   (t (let ((sub-lcm (euler5 (rest l) (1+ depth))))
		(format t "l:~D sl:~D m:~D d:~D~D"
				l sub-lcm (multiplep sub-lcm (first l)) depth #\Newline)
		(if (multiplep sub-lcm (first l))
			sub-lcm
		  (* (first l) sub-lcm))))))

(defun pair-sum (num list)
  (when list
	(let ((n (member (- num (car list)) (cdr list))))
	  (if n (list (car list) (car n))
			(pair-sum num (rest list))))))

(defun euler44 ()
  (do* ((index 1 (1+ index))
		(pent 1 (* index (/ (1- (* 3 index)) 2)))
		(pents nil (cons pent pents))
		(pair nil (pair-sum pent pents)))
	  ((and pair (member (apply '- pair) pents)) pair)
	(myprint pent :indent (if pair 0 1))))
